package cate.game.client.msg;

import cate.common.table.d.GDOperation;
import cate.common.util.GameResult;
import cate.game.GameBody;
import cate.game.client.ClientContext;
import cate.game.client.msg.id.MsgIdBLogin;
import cate.game.common.Performable;
import cate.game.framework.GameException;
import cate.game.framework.ThreadShare;
import cate.game.log.GameLoggerFactory;
import cate.game.role.Role;
import cate.game.role.login.msg.LoginFailedResp;
import cate.game.util.ct.CT;
import easy.java.practice.errorcode.EcException;
import org.slf4j.Logger;

import java.util.concurrent.Callable;

public interface MsgInput extends Msg {

    default void handle(GameBody game, GameMsg msg) {
        try {
            ClientContext cc = game.client.contextHolder.getMust(msg.context);
            cc.setActiveTime(System.currentTimeMillis());
            CT.gs(game.config.srvId).nMsgInput++;
            boolean success = ThreadShare.instance().roleExe(cc, () -> {
                doExecute(game, cc);
            }, this.getClass().getName());
            if(!success){
                if(cc.getRole() != null){
                    cc.getRole().getGame().notice.message(cc.getRole(), "服务器开小差啦，请稍后再尝试");
                }else{
                    if(msg.idA == 1 && msg.idB == MsgIdBLogin.CHECK_REQ.b){
                        cc.sendNow(new LoginFailedResp(2));
                    }else if(msg.idA == 1 && msg.idB == MsgIdBLogin.START_REQ.b){
                        cc.sendNow(new LoginFailedResp(1));
                    }else if(msg.idA == 1 && msg.idB == MsgIdBLogin.ROLE_INIT_REQ.b){
                        cc.sendNow(new LoginFailedResp(3));
                    }
                }
            }
        } catch (Exception e) {
            game.client.request.onMsgInputException(game, msg, e);
        }
    }

    default void doExecute(GameBody game, ClientContext cc) {
        try {
            game.commandExecutor.execute(this, game, cc);
        } catch (EcException e) {
            if(cc.getRole() != null) {
                game.notice.message(cc.getRole(), e.message);
            }
            game.client.request.onMsgInputException(game, null, e);
        }
    }

    void execute(GameBody game, ClientContext cc);

    default void perform(GameBody game, Role role, Performable runnable) {
        try {
            if(getOperation() != GDOperation.NULL) {
                role.log.setOperation(getOperation());
            }
            runnable.run();
        } catch (GameException e) {
            game.notice.message(role, e.toResult());
        } catch (Exception e) {
            game.notice.message(role, e);
            Logger logger = GameLoggerFactory.getLogger(game, this.getClass());
            logger.error("", e);
        } finally {
            if(role != null) {
                role.log.clearOperation();
            }
        }
    }

    default void perform(GameBody game, Role role, Callable<GameResult> callable) {
        try {
            if(getOperation() != GDOperation.NULL) {
                role.log.setOperation(getOperation());
            }
            GameResult r = callable.call();
            if(!r.ok()) {
                game.notice.message(role, r);
            }
        } catch (GameException e) {
            game.notice.message(role, e.toResult());
        } catch (Exception e) {
            game.notice.message(role, e);
            Logger logger = GameLoggerFactory.getLogger(game, this.getClass());
            logger.error("", e);
        } finally {
            if(role != null) {
                role.log.clearOperation();
            }
        }
    }

    default int getOperation() {
        return GDOperation.NULL;
    }

}
